#pragma once

#include <pthread.h>
#include <functional>
#include "Socket.hpp"

using namespace SocketModule;

using service_t = std::function<std::string(std::string)>;

static const uint16_t g_port = 8888;

class TcpServer
{
private:
    void Service(Inet_Addr &addr, SockSPtr &newsock)
    {
        while (true)
        {
            std::string msg;
            ssize_t n = newsock->Recv(&msg);
            if (n <= 0)
            {
                LOG(FATAL, "recv falied\n");
                break;
            }
            // std::cout << msg << std::endl;

            std::string echo_str = "[" + addr.AddrStr() + "]# ";
            echo_str += msg;
            std::cout << echo_str << std::endl; // 放在服务器端看到数据
            if (newsock->Send(echo_str) < 0)
            {
                LOG(FATAL, "send falied\n");
                break;
            }
        }

        newsock->Close();
    }

    static void *Execute(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_self->Service(td->_addr, td->_newsock);
        delete td;
        td->_newsock->Close();
        return nullptr;
    }

public:
    TcpServer(uint16_t port = g_port)
        : _port(port), _sockfd(std::make_shared<TcpSocket>()), _isrunning(false)
    //,_service(service)
    {
        _sockfd->BuildListenSocket(_port);
    }

    ~TcpServer()
    {
    }

    class ThreadData
    {
    public:
        ThreadData(Inet_Addr addr, SockSPtr newsock, TcpServer *self)
            : _addr(addr), _newsock(newsock), _self(self)
        {
            // std::cout << "   class ThreadData" << std::endl;
        }
        ~ThreadData() {}

    public:
        Inet_Addr _addr;
        SockSPtr _newsock;
        TcpServer *_self;
    };

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            Inet_Addr addr;
            SockSPtr newsock = _sockfd->Accepter(&addr);
            if (newsock == nullptr)
                continue;
            LOG(INFO, "get a link, client info is: %s, sockfd is: %d\n", addr.AddrStr().c_str(), newsock->Sockfd());
            // Service(addr,newsock);
            pthread_t tid;
            ThreadData *td = new ThreadData(addr, newsock, this);
            pthread_create(&tid, nullptr, Execute, td);
        }
        _isrunning = false;
    }

private:
    uint16_t _port;   // 端口
    SockSPtr _sockfd; // socket 对象
    bool _isrunning;  // 服务器状态
    // service_t _service; // 回调的业务函数
};